From 3e43dda9d419f16cef5426576f7819962849ef7f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 21 Oct 2020 20:28:30 -0400 Subject: [PATCH] modelbutton: Recreate our AT context When the button role changes, we want to update the accessible role to match. Since accessible roles are unchangeable post-creation of the AT context, we have to cheat a bit and recreate the whole context. --- gtk/gtkmodelbutton.c | 111 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c index 7a7b10d76a..31d0bf10c5 100644 --- a/gtk/gtkmodelbutton.c +++ b/gtk/gtkmodelbutton.c @@ -45,6 +45,7 @@ #include "gtkshortcuttrigger.h" #include "gtkshortcutcontroller.h" #include "gtkshortcut.h" +#include "gtkaccessibleprivate.h" /** * SECTION:gtkmodelbutton @@ -175,6 +176,8 @@ struct _GtkModelButton guint open_timeout; GtkEventController *controller; + GtkATContext *at_context; + guint active : 1; guint centered : 1; guint iconic : 1; @@ -190,7 +193,11 @@ struct _GtkModelButtonClass }; static void gtk_model_button_actionable_iface_init (GtkActionableInterface *iface); + +static void gtk_model_button_accessible_iface_init (GtkAccessibleInterface *iface); + G_DEFINE_TYPE_WITH_CODE (GtkModelButton, gtk_model_button, GTK_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE (GTK_TYPE_ACCESSIBLE, gtk_model_button_accessible_iface_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_model_button_actionable_iface_init)) GType @@ -295,6 +302,50 @@ gtk_model_button_actionable_iface_init (GtkActionableInterface *iface) iface->set_action_target_value = gtk_model_button_set_action_target_value; } +static GtkATContext * +create_at_context (GtkModelButton *button) +{ + GdkDisplay *display = _gtk_widget_get_display (GTK_WIDGET (button)); + GtkAccessibleRole role; + + switch (button->role) + { + default: + case GTK_BUTTON_ROLE_NORMAL: + case GTK_BUTTON_ROLE_TITLE: + role = GTK_ACCESSIBLE_ROLE_MENU_ITEM; + break; + case GTK_BUTTON_ROLE_CHECK: + role = GTK_ACCESSIBLE_ROLE_MENU_ITEM_CHECKBOX; + break; + case GTK_BUTTON_ROLE_RADIO: + role = GTK_ACCESSIBLE_ROLE_MENU_ITEM_RADIO; + break; + } + + return gtk_at_context_create (role, GTK_ACCESSIBLE (button), display); +} + +static GtkATContext * +gtk_model_button_get_at_context (GtkAccessible *accessible) +{ + GtkModelButton *button = GTK_MODEL_BUTTON (accessible); + + if (button->at_context == NULL) + button->at_context = create_at_context (button); + + return button->at_context; +} + +static void +gtk_model_button_accessible_iface_init (GtkAccessibleInterface *iface) +{ + GtkAccessibleInterface *parent_iface = g_type_interface_peek_parent (iface); + + iface->get_at_context = gtk_model_button_get_at_context; + iface->get_platform_state = parent_iface->get_platform_state; +} + static void update_node_ordering (GtkModelButton *button) { @@ -518,6 +569,35 @@ update_node_name (GtkModelButton *self) } } +static void +update_accessible_properties (GtkModelButton *button) +{ + if (button->menu_name || button->popover) + gtk_accessible_update_property (GTK_ACCESSIBLE (button), + GTK_ACCESSIBLE_PROPERTY_HAS_POPUP, TRUE, + -1); + else + gtk_accessible_reset_property (GTK_ACCESSIBLE (button), + GTK_ACCESSIBLE_PROPERTY_HAS_POPUP); + + if (button->popover) + gtk_accessible_update_relation (GTK_ACCESSIBLE (button), + GTK_ACCESSIBLE_RELATION_CONTROLS, g_list_append (NULL, button->popover), + -1); + else + gtk_accessible_reset_relation (GTK_ACCESSIBLE (button), + GTK_ACCESSIBLE_RELATION_CONTROLS); + + if (button->role == GTK_BUTTON_ROLE_CHECK || + button->role == GTK_BUTTON_ROLE_RADIO) + gtk_accessible_update_state (GTK_ACCESSIBLE (button), + GTK_ACCESSIBLE_STATE_CHECKED, button->active, + -1); + else + gtk_accessible_reset_state (GTK_ACCESSIBLE (button), + GTK_ACCESSIBLE_STATE_CHECKED); +} + static void gtk_model_button_set_role (GtkModelButton *self, GtkButtonRole role) @@ -541,6 +621,10 @@ gtk_model_button_set_role (GtkModelButton *self, update_node_name (self); gtk_model_button_update_state (self); + g_set_object (&self->at_context, create_at_context (self)); + + update_accessible_properties (self); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ROLE]); } @@ -622,31 +706,14 @@ gtk_model_button_set_active (GtkModelButton *button, return; button->active = active; + + update_accessible_properties (button); + gtk_model_button_update_state (button); gtk_widget_queue_draw (GTK_WIDGET (button)); g_object_notify_by_pspec (G_OBJECT (button), properties[PROP_ACTIVE]); } -static void -update_accessible_properties (GtkModelButton *button) -{ - if (button->menu_name || button->popover) - gtk_accessible_update_property (GTK_ACCESSIBLE (button), - GTK_ACCESSIBLE_PROPERTY_HAS_POPUP, TRUE, - -1); - else - gtk_accessible_reset_property (GTK_ACCESSIBLE (button), - GTK_ACCESSIBLE_PROPERTY_HAS_POPUP); - - if (button->popover) - gtk_accessible_update_relation (GTK_ACCESSIBLE (button), - GTK_ACCESSIBLE_RELATION_CONTROLS, g_list_append (NULL, button->popover), - -1); - else - gtk_accessible_reset_relation (GTK_ACCESSIBLE (button), - GTK_ACCESSIBLE_RELATION_CONTROLS); -} - static void gtk_model_button_set_menu_name (GtkModelButton *button, const char *menu_name) @@ -942,12 +1009,14 @@ gtk_model_button_set_property (GObject *object, } static void -gtk_model_button_dispose (GObject *object) +gtk_model_button_dispose (GObject *object) { GtkModelButton *model_button = GTK_MODEL_BUTTON (object); g_clear_pointer (&model_button->menu_name, g_free); + g_clear_object (&model_button->at_context); + G_OBJECT_CLASS (gtk_model_button_parent_class)->dispose (object); } -- 2.30.2